package edu.hcmus.sow.web;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import edu.hcmus.sow.dao.ClientDAO;
import edu.hcmus.sow.dao.SiteDAO;
import edu.hcmus.sow.dao.UserDAO;
import edu.hcmus.sow.dao.UserProfileDAO;
import edu.hcmus.sow.domain.Client;
import edu.hcmus.sow.domain.Site;
import edu.hcmus.sow.domain.User;
import edu.hcmus.sow.domain.UserProfile;
import edu.hcmus.sow.service.ClientService;
import edu.hcmus.sow.service.RepositoryService;
import edu.hcmus.sow.service.UserService;

@Controller
public class ClientController {
   @Autowired
   private ClientDAO clientDAO;

   @Autowired
   private SiteDAO siteDAO;

   @Autowired
   private UserDAO userDAO;

   @Autowired
   private UserService userService;

   @Autowired
   private UserProfileDAO userProfileDAO;

   @Autowired
   private ClientService clientService;

   @Autowired
   private RepositoryService repositoryService;

   @RequestMapping(value = "/clients")
   public String display() {
      return "clients";
   }

   @RequestMapping("/clients/search")
   @ResponseBody
   public List<Map<String, String>> search(@RequestParam(value = "name", required = false) String name,
         @RequestParam(value = "subdomain", required = false) String subdomain) {

      List<Map<String, String>> result = new ArrayList<Map<String, String>>();
      List<Client> clients = clientDAO
            .findByCriteria(StringUtils.trimToEmpty(name), StringUtils.trimToEmpty(subdomain));

      for (Client client : clients) {
         Map<String, String> map = new HashMap<String, String>();
         map.put("id", client.getId().toString());
         map.put("name", client.getName());
         map.put("email", client.getContactEmail());
         map.put("phone", client.getPhone());
         map.put("status", "Y".equals(client.getStatus()) ? "true" : "false");
         map.put("subdomain", client.getSite() == null ? "" : client.getSite().getSubDomain());
         result.add(map);
      }

      return result;
   }

   @RequestMapping("/ajax/client")
   public ModelAndView displayClient(@RequestParam(value = "id", required = false) Integer id) {
      ClientForm clientForm = new ClientForm();
      if (id != null) {
         Client client = clientDAO.findById(id);
         clientForm.setId(id);
         clientForm.setName(client.getName());
         clientForm.setSubDomain(client.getSite().getSubDomain());
         clientForm.setStatus("Y".equals(client.getStatus()));
         clientForm.setEmail(client.getContactEmail());
         clientForm.setPhone(client.getPhone());
      }

      ModelAndView mav = new ModelAndView();
      mav.addObject("clientForm", clientForm);
      mav.setViewName("client_form");
      return mav;
   }

   @RequestMapping(value = "/ajax/client/save", method = RequestMethod.POST)
   public ModelAndView saveClient(@Valid ClientForm clientForm, BindingResult result) {
      clientForm.validate(result, siteDAO);

      if (!result.hasErrors()) {
         if (clientForm.getId() == null) {
            repositoryService.createFileStorage(clientForm.getSubDomain().trim());
         }
         Client client = clientService.saveClient(clientForm.getId(), clientForm.getName(), clientForm.getEmail(),
               clientForm.getPhone(), clientForm.getStatus());
         clientService.saveSite(client, clientForm.getSubDomain());
         clientForm.setId(client.getId());
      }

      ModelAndView mav = new ModelAndView();
      mav.addObject("clientForm", clientForm);
      mav.addObject("hasErrors", result.hasErrors());
      mav.setViewName("client_form");
      return mav;
   }

   @RequestMapping(value = "/ajax/client/delete", method = RequestMethod.POST)
   @ResponseBody
   public String deleteClient(@RequestParam(value = "id", required = true) Integer id) {
      Client c = clientService.getClientByID(id);
      Site s = c.getSite();
      if (clientService.deleteClient(id)) {
         repositoryService.dropFileStorage(s.getSubDomain());
         return "success";
      }
      return "error";
   }

   @RequestMapping("/client/{id}")
   public ModelAndView display(@PathVariable("id") int id) {
      // Client details
      Client client = clientDAO.findById(id);
      ClientForm clientForm = new ClientForm();
      clientForm.setId(client.getId());
      clientForm.setName(client.getName());
      clientForm.setSubDomain(client.getSite() == null ? "" : client.getSite().getSubDomain());
      clientForm.setStatus("Y".equals(client.getStatus()) ? true : false);
      clientForm.setEmail(client.getContactEmail());
      clientForm.setPhone(client.getPhone());

      // Site details
      Site site = client.getSite();
      SiteForm siteForm = new SiteForm();
      siteForm.setId(site.getId());
      siteForm.setSubDomain(site.getSubDomain());
      siteForm.setNumberOfUsers(site.getNumberOfUsers() == null ? null : site.getNumberOfUsers() + "");
      siteForm.setStorageLimit(site.getStorageLimit() == null ? null : site.getStorageLimit() + "");
      siteForm.setRenewDate(site.getRenewDate() == null ? null : new SimpleDateFormat("MM/dd/yyyy").format(site
            .getRenewDate().getTime()));
      siteForm.setDefaultLanguage(site.getDefaultLanguage());
      siteForm.setShortDateFormat(site.getShortDateFormat());

      // Administrator account
      User user = client.getSite().getUser() == null ? null : client.getSite().getUser();
      UserForm userForm = new UserForm();
      if (user != null) {
         UserProfile profile = userProfileDAO.getByUserID(user.getId());
         userForm.setId(user.getId());
         userForm.setUsername(profile.getUserByUserId().getUsername());
         userForm.setEnabled(profile.getUserByUserId().getEnabled());
         userForm.setFirstName(profile.getFirstName());
         userForm.setLastName(profile.getLastName());
         userForm.setMiddleName(profile.getMiddleName());
      }

      ModelAndView mav = new ModelAndView();
      mav.addObject("clientID", id);
      mav.addObject("clientForm", clientForm);
      mav.addObject("siteForm", siteForm);
      mav.addObject("userForm", userForm);
      mav.setViewName("client_detail");
      return mav;
   }

   @RequestMapping(value = "/ajax/client/update", method = RequestMethod.POST)
   public ModelAndView updateClient(@Valid ClientForm clientForm, BindingResult result) {
      if (result.getAllErrors().size() <= 1) { // sub domain empty
         clientService.saveClient(clientForm.getId(), clientForm.getName(), clientForm.getEmail(),
               clientForm.getPhone(), clientForm.getStatus());
      }

      ModelAndView mav = new ModelAndView();
      mav.addObject("clientForm", clientForm);
      mav.addObject("hasErrors", Boolean.valueOf(result.getAllErrors().size() > 1));
      mav.setViewName("client_profile_form");
      return mav;
   }

   @RequestMapping(value = "/ajax/client/site/update", method = RequestMethod.POST)
   public ModelAndView updateSite(@Valid SiteForm siteForm, BindingResult result) {
      siteForm.validate(result, siteDAO);

      if (!result.hasErrors()) {
         clientService.saveSite(siteForm.getId(), siteForm.getSubDomain(), siteForm.getNumberOfUsersInt(),
               siteForm.getStorageLimitInt(), siteForm.getRenewDateDt(), siteForm.getDefaultLanguage(),
               siteForm.getShortDateFormat());
      }

      ModelAndView mav = new ModelAndView();
      mav.addObject("siteForm", siteForm);
      mav.addObject("hasErrors", result.hasErrors());
      mav.setViewName("site_form");
      return mav;
   }

   @RequestMapping(value = "/ajax/client/{id}/user/update", method = RequestMethod.POST)
   public ModelAndView updateUser(@PathVariable("id") int id,
         @RequestParam(value = "id", required = false) Integer userId, @Valid UserForm userForm, BindingResult result) {
      userForm.validate(result, userDAO);

      userForm.setId(userId);
      if (!result.hasErrors()) {
         System.out.println(userId + userForm.getUsername() + userForm.getPassword());
         User user = userService.saveUser(userId, userForm.getUsername(), userForm.getPassword(), true, id);
         userService.saveUserProfile(user, userForm.getFirstName(), userForm.getLastName(), userForm.getMiddleName(),
               userForm.getEmail(), userForm.getPhone());
         userService.updateUserRole(user, 2);

         Client c = clientService.getClientByID(id);
         Site s = c.getSite();
         s.setUser(user);
         clientService.saveSite(s);
         userForm.setId(user.getId());
      }

      ModelAndView mav = new ModelAndView();
      mav.addObject("userForm", userForm);
      mav.addObject("hasErrors", result.hasErrors());
      mav.setViewName("user_profile_form");
      return mav;
   }

   @RequestMapping(value = "/ajax/client/{id}/delete", method = RequestMethod.POST)
   public String ajaxDeleteClient(@PathVariable("id") Integer id) {
      Client c = clientService.getClientByID(id);
      Site s = c.getSite();
      if (clientService.deleteClient(id)) {
         repositoryService.dropFileStorage(s.getSubDomain());
         return "redirect:/clients";
      }
      return "error";
   }
}
